(use 'clojure.contrib.repl-utils)
(use 'clojure.contrib.str-utils)
(use 'clojure.contrib.classpath)
(require 'clj-doc.core 'clj-doc.generator.default)

(def libs
  '(
    clojure.core
    clojure.main
    ; clojure.inspector
    ; clojure.parallel
    clojure.set
    clojure.xml
    clojure.zip
    clojure.contrib.accumulators
    ;clojure.contrib.apply-macro
    clojure.contrib.combinatorics
    clojure.contrib.command-line
    clojure.contrib.complex-numbers
    clojure.contrib.cond
    clojure.contrib.condt
    clojure.contrib.def
    clojure.contrib.duck-streams
    clojure.contrib.error-kit
    clojure.contrib.except
    clojure.contrib.fcase
    clojure.contrib.generic
    clojure.contrib.generic.arithmetic
    clojure.contrib.generic.collection
    clojure.contrib.generic.comparison
    clojure.contrib.generic.functor
    clojure.contrib.generic.math-functions
    clojure.contrib.import-static
    clojure.contrib.jar
    clojure.contrib.javadoc.browse
    clojure.contrib.json.read
    clojure.contrib.json.write
    clojure.contrib.lazy-seqs
    clojure.contrib.lazy-xml
    clojure.contrib.macro-utils
    clojure.contrib.macros
    clojure.contrib.math
    clojure.contrib.miglayout
    clojure.contrib.mmap
    clojure.contrib.monads
    clojure.contrib.ns-utils
    clojure.contrib.pprint
    clojure.contrib.probabilities.finite-distributions
    clojure.contrib.probabilities.monte-carlo
    clojure.contrib.probabilities.random-numbers
    clojure.contrib.prxml
    clojure.contrib.repl-ln
    clojure.contrib.repl-utils
    clojure.contrib.seq-utils
    clojure.contrib.server-socket
    clojure.contrib.set
    clojure.contrib.shell-out
    clojure.contrib.sql
    clojure.contrib.stacktrace
    clojure.contrib.str-utils
    clojure.contrib.stream-utils
    clojure.contrib.swing-utils
    clojure.contrib.template
    clojure.contrib.trace
    clojure.contrib.types
    clojure.contrib.walk
    clojure.contrib.zip-filter
    ))

(defn make-inside-box-url [relative-path]
    (str "file:///" (apply str (replace {\\ \/} (System/getenv "ACB_HOME"))) relative-path ))

; (add-classpath (make-inside-box-url "/usr/lib/clojure-contrib.jar"))
; (add-classpath (make-inside-box-url "/usr/src/"))

;(println (seq (.getURLs (java.lang.ClassLoader/getSystemClassLoader))))
(defn get-classpath []
    (into (seq (.getURLs (clojure.lang.RT/baseLoader)))
        (seq (.getURLs (java.lang.ClassLoader/getSystemClassLoader)))))

(def . (str (System/getenv "ACB_HOME") "\\usr\\src\\"))

(defn pr-dbg [x]
    (binding [*print-dup* true]
        (pr-str x)))

;ver de cambiar por classpath-directories en clojure.contrib.classpath
(defn- find-and-complete-path [file-name]
    (if (.exists (java.io.File. file-name))
        file-name
        (loop [clpath (get-classpath)]
            (if (not (empty? clpath))
                (let [abs-path (re-gsub #"file:\/" "" (.toString (first clpath)))
                      abs-file-path (str abs-path file-name ".clj")]
                    (if (.exists (java.io.File. abs-file-path))
                        abs-file-path
                        (recur (rest clpath))))))))

;tuple = {:arglists :ns :name :file :line :doc :tag}
(defn- make-completions []
	(clj-doc.core/ensure-required libs)
    (clj-doc.core/generate libs (fn [ns-syms var-tuples]
                                    (let [sorted-var-tuples
                                            (sort-by (fn [[ns-sym var-sym var-meta]] [var-sym ns-sym]) var-tuples)
                                          var-contents
                                            (map (fn [[ns-sym var-sym tuple-map]]
                                                    tuple-map)
                                                sorted-var-tuples)]
                                        var-contents))))

(defn- write-fn-completions-bind [file-path l-fn]
    (let [completions (make-completions)]
        (with-open [a-stream (new java.io.FileWriter file-path)]
            (binding [*out* a-stream]
                (l-fn completions))))
    (println "done!"))

(defn- ellipsize [some-str maxchars]
    (if (> (count some-str) maxchars)
        (str (subs some-str 0 (- maxchars 3)) "...")
        some-str))

(defn- get-special-forms []
    (str-join " \\\n" #{"#Special_Forms" "." "&" "catch" "def" "do" "fn" "if" "finally" "let" "loop" "monitor-enter" "monitor-exit" "new" "quote" "recur" "set!" "throw" "try" "var"}))

(defn make-api
    "Recreate the clojure API file that SciTE use for inline help and autocompletion."
    []
    (write-fn-completions-bind (str (System/getenv "ACB_HOME") "\\bin\\scite\\api\\clojure.api")
        #(loop [loop-completions %]
            (let [kw (first loop-completions)
                  rest-completions (rest loop-completions)]
                (let [arglist (if (nil? (:arglists kw)) '("") (:arglists kw))]
                    (doseq [arg arglist]
                        (println (str (:name kw) " " arg " \\n"
                            "ns: " (:ns kw) (when (:macro kw) " - Macro") "\\n"
                            (ellipsize (.replace (str " " (:doc kw)) "\n" "\\n") 1500)))))

                    (if (not (== (count rest-completions) 0))
                        (recur rest-completions))))))

(defn make-keywords
    "Recreate the clojure set of keywords that SciTE use for keywords recognition."
    []
    (write-fn-completions-bind (str (System/getenv "ACB_HOME") "\\bin\\scite\\config\\clojure-keywords.properties")
        #(doseq [x %]
            (let [x-name (:name x)]
                (cond
                    (= x (first %)) (println (str "keywords.$(file.patterns.clj)= " x-name " \\"))
                    (= x (last %)) (println (str x-name (get-special-forms)))
                    true (println (str x-name " \\")))))))

(defn make-help []
    (let [doc-root (str (System/getenv "ACB_HOME") "\\usr\\doc\\clj-doc\\")]
        (clj-doc.core/generate-and-write
            libs
              #(clj-doc.generator.default/generate  %1 %2
                    {:title "clj-doc: Clojure Library Documentation"})
            doc-root)))

(defn bye []
    (java.lang.System/exit 0))

(defn dbg
    "Open file-name arg in JSwat for debug purpose. If load optional arg is true, load file-name before call JSwat."
    [file-name & load?]
    (do
        (if load? (load file-name))
            (doto (new ProcessBuilder [(str (System/getenv "ACB_HOME") "\\bin\\jswat-4.4\\bin\\jswat.exe")
                                        "-J-Djswat.transport=dt_socket"
                                        "-J-Djswat.address=localhost:8888"
                                        (find-and-complete-path file-name)])
                (.directory (new java.io.File (str (System/getenv "ACB_HOME"))))
                (.start))))

(defn ed
    "Open file-name file using SciTE editor"
    [file-name]
    (doto
        (new ProcessBuilder [(str (System/getenv "ACB_HOME") "\\bin\\scite\\scite.exe") (find-and-complete-path file-name)])
        (.start)))
